package com.example.yian.controller;

import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.word.WordExportUtil;
import com.aliyun.oss.*;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.yian.config.OssConfig;
import com.example.yian.entity.*;
import com.example.yian.service.*;
import com.example.yian.util.FileUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

import static cn.afterturn.easypoi.entity.ImageEntity.*;

@RestController
public class SecurityRiskExportController {

    @Autowired
    private SecurityRiskService riskService;

    @Autowired
    private ProjectInfoService projectInfoService;

    @Autowired
    private OssConfig ossConfig;

    @Autowired
    private FileUtil fileUtil;

    @Autowired
    private SecurityRiskReportService reportService;

    @Autowired
    private WeChatAuthService weChatAuthService;

    @Autowired
    private TextSearchService textSearchService;

    @Autowired
    private MoonShotService moonshotService;

    @Autowired
    private RiskRectificationService riskRectificationService;

    private static final Logger log = LoggerFactory.getLogger(SecurityRiskController.class);

    @PostMapping("/addRiskReport")
    public  Map<String, Object> addReport(HttpServletResponse Response, @RequestBody Map<String, Object> requestParams,
                                          @RequestHeader("Authorization") String token) throws Exception {
        Map<String, Object> response = new HashMap<>();
        Map<String, Object> map = new HashMap<>();
        ProjectInfo curInfo = new ProjectInfo();
        ObjectMapper mapper = new ObjectMapper();
        String strRiskId = new String();
        String strRiskIds = new String();
        List<Map<String, Object>> imageList = new ArrayList<>();
        List<Optional<TextSearchResponse>> textResponseList = new ArrayList<>();
        Long[] riskIds = new Long[0];

        Optional<Long> userIdOpt = weChatAuthService.getUserIdFromToken(token);
        if (!userIdOpt.isPresent()) {
            response.put("code", 401);
            response.put("msg", "未授权");
            response.put("time", Instant.now().toEpochMilli());
            response.put("data", new HashMap<>());
            return response;
        }
        Long userId = userIdOpt.get();

        //解析全选标志
        Boolean selectAllFlag = requestParams.get("selectAllFlag") != null
                ? Boolean.parseBoolean(requestParams.get("selectAllFlag").toString())
                : false;
        if (selectAllFlag) {
            Integer pageNum = (Integer) requestParams.getOrDefault("page", 1);
            Integer pageSize = (Integer) requestParams.getOrDefault("size", 1000);
            String  startTime = (String) requestParams.getOrDefault("startTime", "2024-03-03");
            log.info("addRiskReport | startTime:{}",startTime);
            if (Objects.equals(startTime, "")) {
                startTime = (String) "2024-03-03";
            }
            String endTime = (String) requestParams.getOrDefault("endTime", "2099-08-15");
            log.info("addRiskReport | endTime:{}",endTime);
            if (Objects.equals(endTime, "")) {
                endTime = (String) "2099-08-15";
            }

            IPage<SecurityRisk> riskPage = riskService.getRiskListsByUserId(userId, pageNum, pageSize, startTime,endTime, 0);
            //重新拿取一把
            List<SecurityRisk> risks = riskPage.getRecords();

            if(risks.size() == 0)
            {
                log.error("addRiskReport | risks is empty");
            }

            riskIds = risks.stream()
                    .map(SecurityRisk::getId)
                    .toArray(Long[]::new);

            if(riskIds.length == 0)
            {
                log.error("addRiskReport |,SelectAll, risks is empty");
            }
        }
        else {
            //非全选
            strRiskIds = requestParams.get("riskIds").toString();
            log.info("addRiskReport | received riskIds:{}",strRiskIds);

            String[] stringItems = strRiskIds.split(",");
            List<String> trimmedItems = Arrays.stream(stringItems)
                    .map(String::trim)
                    .collect(Collectors.toList());

            // 记录解析后的 stringItems 内容
            log.error("addRiskReport | Parsed riskIds: {}", trimmedItems);

            // 将字符串数组转换为 Long 数组

            try {
                riskIds = Arrays.stream(stringItems)
                        .map(Long::parseLong)
                        .toArray(Long[]::new);
            } catch (NumberFormatException e) {
                System.err.println("Invalid number format in the input string.");
                response.put("code", 500);
                response.put("msg", "解析riskIds失败");
                response.put("data", "");
                return response;
            }
        }

        // 假设riskIds数组至少有一个元素
        for (Long riskId : riskIds) {
            Optional<SecurityRisk> risk = riskService.getSecurityRiskWithDetails(riskId);

            if (risk.isEmpty()) {
                response.put("code", 200);
                response.put("msg", "隐患不存在");
                response.put("data", "");
                return response;
            }

           // Long userId = risk.get().GetUserId();

            if (userId == null) {
                response.put("code", 200);
                response.put("msg", "用户不存在");
                response.put("data", "");
                return response;
            }
            Optional<ProjectInfo> projectInfo = projectInfoService.getProjectInfoByUserId(userId);
            if (projectInfo.isEmpty()) {
                response.put("code", 200);
                response.put("msg", "项目信息不存在");
                response.put("data", "");
                return response;
            }
            curInfo = projectInfo.get();

            Optional<SecurityRisk> detail = riskService.getSecurityRiskWithDetails(riskId);

            log.info("addRiskReport | riskId :{}, textId:{}" ,riskId, detail.get().getTextId());

            Optional<TextSearchResponse> textResponse = textSearchService.findByTextId(detail.get().getTextId());

            if (textResponse.isEmpty()) {
                log.info("addRiskReport | response is not found by textId:{}", detail.get().getTextId());
                response.put("code", 200);
                response.put("msg", "文本信息不存在");
                response.put("data", "");
                return response;
            }
            ImageEntity image = new ImageEntity();
            image.setWidth(300);
            image.setHeight(100);
            String imageUrlAry = risk.get().getImage();
            String firstImageUrl = imageUrlAry.split(",", 2)[0];
            log.info("export image url:{}",firstImageUrl);
            image.setUrl(firstImageUrl);
            image.setType(URL);

            Map<String, Object> singleRecord = new HashMap<>();

            Optional<RiskRectification> rectificationOpt = Optional.ofNullable(riskRectificationService.getRectificationByRiskId(risk.get().getId()));
            if(rectificationOpt.isPresent())
            {
                ImageEntity rectificationImage = new ImageEntity();
                rectificationImage.setWidth(300);
                rectificationImage.setHeight(100);
                String rectificationImageUrlAry = rectificationOpt.get().getImage();
                String rectificationFirstImageUrl = rectificationImageUrlAry.split(",", 2)[0];
                log.info("export image url:{}",rectificationFirstImageUrl);
                rectificationImage.setUrl(rectificationFirstImageUrl);
                rectificationImage.setType(URL);
                singleRecord.put("rectificationImage",rectificationImage);
            }

            singleRecord.put("riskImage",image);
            singleRecord.put("riskContent",textResponse.get().getContent());
            singleRecord.put("rectificationContent",detail.get().getSupplementContents());

            imageList.add(singleRecord);

            textResponseList.add(textResponse);
        }

        //原来的方法仍然保持
        map.put("project_name", curInfo.getProjectName());
        map.put("contruction_unit", curInfo.getConstructionUnit());
        map.put("design_unit", curInfo.getDesignUnit());
        map.put("supervision_unit", curInfo.getSupervisionUnit());
        map.put("inspection_team_name", curInfo.getInspectionTeamName());
        map.put("inspection_personnel", curInfo.getInspectionPersonnel());
        map.put("riskResponseList",textResponseList);

        //建议
        String strResponseContent = "请结合一下内容，总结存在的问题以及建议，尽量控制在100字以内:";
        for(int i=0;i<textResponseList.size();i++)
        {
            strResponseContent = strResponseContent +textResponseList.get(i).get().getContent();
        }

        String strSuggestion = moonshotService.callMoonshotAPI("sk-szywcJVpxK7xTGkX2ZE4GcdRb1tow9abyOobWbKmRj0AMpgd", strResponseContent, "请结合以上内容，总结出来存在的问题及建议");
        map.put("suggestion", strSuggestion);
        map.put("imageList", imageList);

        SecurityRiskReport riskReport = new SecurityRiskReport();

        ClassPathResource resource = new ClassPathResource("Templates/Template.docx");
        // 从 InputStream 创建临时文件
        File tempFile = File.createTempFile("temp", ".docx");
        try (InputStream inputStream = resource.getInputStream(); // 获取 InputStream
             FileOutputStream fos = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        String templatePath = tempFile.getAbsolutePath();
        XWPFDocument word = WordExportUtil.exportWord07(tempFile.getAbsolutePath(), map);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        word.write(byteArrayOutputStream);

        //代替
        OSS ossClient = null;
        String url = null;
        String reportId = null;

        // 使用临时文件路径调用 WordExportUtil.exportWord07
        try {
            // 4. 上传到OSS
            reportId = UUID.randomUUID().toString();
            String fileName = reportId + ".docx"; // 添加扩展名
            ossClient = new OSSClientBuilder().build(
                    ossConfig.getEndpoint(),
                    ossConfig.getAccessKeyId(),
                    ossConfig.getAccessKeySecret()
            );

            // 将字节数组转换为输入流
            InputStream fileInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

            // 上传文件到OSS
            ossClient.putObject(new PutObjectRequest(ossConfig.getBucketName(), fileName, fileInputStream));

            // 获取文件URL
            url = "https://" + ossConfig.getBucketName() + "." + ossConfig.getEndpoint() + "/" + fileName;


            reportService.addReport(url, curInfo.getUserId(), reportId);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 删除临时文件
            Files.deleteIfExists(Paths.get(tempFile.getAbsolutePath()));
        }

        response.put("code", 200);
        response.put("msg", "成功");
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("url", url);
        responseData.put("ReportId", reportId);
        response.put("data", responseData);
        return response;
    }

    @PostMapping("/getHisReport")
    public Map<String, Object> getReportList(
            @RequestBody Map<String, Object> requestParams,
            @RequestHeader("Authorization") String token) {
        Map<String, Object> response = new LinkedHashMap<>();
        Optional<Long> userIdOpt = weChatAuthService.getUserIdFromToken(token);

        if (!userIdOpt.isPresent()) {
            response.put("code", 401);
            response.put("msg", "未授权");
            response.put("time", Instant.now().toEpochMilli());
            response.put("data", new HashMap<>());
            return response;
        }
        Long userId = userIdOpt.get();
        // 从请求体中提取分页参数
        Integer pageNum = (Integer) requestParams.getOrDefault("page", 1);
        Integer pageSize = (Integer) requestParams.getOrDefault("size", 1000);
        String  startTime = (String) requestParams.getOrDefault("startTime", "2024-03-03");
        Boolean isExportAll = Optional.ofNullable(requestParams.get("isExportAll"))
                .map(o -> {
                    if (o instanceof Boolean) {
                        return (Boolean) o;
                    } else if (o instanceof String) {
                        return Boolean.parseBoolean((String) o);
                    } else {
                        return false; // 默认值
                    }
                })
                .orElse(false); // 默认值为 false
        if (Objects.equals(startTime, "")) {
            startTime = (String) "2024-03-03";
        }
        String endTime = (String) requestParams.getOrDefault("endTime", "2099-08-15");
        if (Objects.equals(endTime, "")) {
            endTime = (String) "2099-08-15";
        }

        Page<SecurityRisk> page = new Page<>(pageNum, pageSize);
        IPage<SecurityRiskReport> riskPage = reportService.getRiskReportListsByUserId(userId, pageNum, pageSize, startTime, endTime, isExportAll);
        response.put("code", 200);
        response.put("msg", "成功");
        response.put("time", Instant.now().toEpochMilli());
        response.put("total", riskPage.getTotal());

        //重新拿取一把
        List<SecurityRiskReport> riskReports = riskPage.getRecords();

        if(riskReports.size() == 0)
        {
            log.error("getHisReport | riskReports is empty");
        }

        List<Map<String, Object>> dataWithExtraFields = new ArrayList<>();
        for (SecurityRiskReport riskReport : riskReports) {
            Map<String, Object> dataItem = new HashMap<>();
            dataItem.put("userId",riskReport.getUserId());
            dataItem.put("ReportId", riskReport.getReportId()); // 假设 otherField 是另一个 Long 类型的字段
            dataItem.put("url",riskReport.getOos_url());
            dataItem.put("createdAt", riskReport.getCreatedAt());
            dataItem.put("updatedAt", riskReport.getUpdatedAt());
            dataWithExtraFields.add(dataItem);
        }
        response.put("data",dataWithExtraFields);
        return response;
    }



    /**
     * 从OSS下载Word文档并返回给客户端
     * @param reportId 报告ID，用于确定文件名
     * @param response HttpServletResponse对象
     * @throws IOException 如果发生IO异常
     */
    @GetMapping("/downloadRiskReport/{reportId}")
    public void downloadWordDocument(@PathVariable String reportId, HttpServletResponse response) throws IOException {
        OSS ossClient = null;
        try {
            ossClient = new OSSClientBuilder().build(
                    ossConfig.getEndpoint(),
                    ossConfig.getAccessKeyId(),
                    ossConfig.getAccessKeySecret()
            );

            // 构建文件名
            String fileName = reportId + ".docx";

            // 创建 GetObjectRequest
            GetObjectRequest getObjectRequest = new GetObjectRequest(ossConfig.getBucketName(), fileName);

            // 从 OSS 下载文件
            OSSObject ossObject = ossClient.getObject(getObjectRequest);

            // 检查 ossObject 是否为 null
            if (ossObject == null) {
                throw new RuntimeException("Failed to get the object from OSS.");
            }

            InputStream inputStream = ossObject.getObjectContent();

            response.reset();
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setContentType("application/msexcel");
            response.setContentType("text/html; charset=UTF-8");
            // 4.设置响应类型为Word文档
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            // 5.中文文件名处理，否则报错
            String encodedFileName = URLEncoder.encode("简介", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + reportId + ".docx");

            // 将文件内容写入到 HTTP 响应输出流
            OutputStream outputStream = response.getOutputStream();
            IOUtils.copy(inputStream, outputStream);
            outputStream.flush();
        } catch (OSSException e) {
            // OSS 服务端异常
            System.err.println("OSS service exception: " + e.getMessage());
        } catch (ClientException e) {
            // 客户端异常
            System.err.println("Client exception: " + e.getMessage());
        } catch (IOException e) {
            // 输入输出异常
            System.err.println("IO exception: " + e.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public File filePath(String modelFileName) {
        // 获取类加载器
        ClassLoader classLoader = FileUtil.class.getClassLoader();
        // 尝试从类路径中加载资源
        URL resource = classLoader.getResource(modelFileName);
        return new File(resource.getFile());
    }


    @GetMapping("/TestaddRiskReport")
    public  Map<String, Object> addReport1(HttpServletResponse Response, @RequestBody String strRiskIds) throws Exception {
        Map<String, Object> response = new HashMap<>();
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> imageList = new ArrayList<>();

        ProjectInfo curInfo = new ProjectInfo();
        List<Optional<TextSearchResponse>> textResponseList = new ArrayList<>();

        // 使用 split 方法按逗号分割字符串
        String[] stringItems = strRiskIds.split(",");

        // 将字符串数组转换为 Long 数组
        Long[] riskIds = new Long[0];
        try {
            riskIds = Arrays.stream(stringItems)
                    .map(Long::parseLong)
                    .toArray(Long[]::new);
        } catch (NumberFormatException e) {
            System.err.println("Invalid number format in the input string.");
            response.put("code", 200);
            response.put("msg", "解析riskIds失败");
            response.put("data", "");
            return response;
        }

        // 假设riskIds数组至少有一个元素
        for (Long riskId : riskIds) {
            Optional<SecurityRisk> risk = riskService.getSecurityRiskWithDetails(riskId);

            if (risk.isEmpty()) {
                response.put("code", 200);
                response.put("msg", "隐患不存在");
                response.put("data", "");
                return response;
            }

            Long userId = risk.get().GetUserId();

            if (userId == null) {
                response.put("code", 200);
                response.put("msg", "用户不存在");
                response.put("data", "");
                return response;
            }
            Optional<ProjectInfo> projectInfo = projectInfoService.getProjectInfoByUserId(userId);
            if (projectInfo.isEmpty()) {
                response.put("code", 200);
                response.put("msg", "项目信息不存在");
                response.put("data", "");
                return response;
            }
            curInfo = projectInfo.get();

            Optional<SecurityRisk> detail = riskService.getSecurityRiskWithDetails(riskId);

            Optional<TextSearchResponse> textResponse = textSearchService.findByTextId(detail.get().getTextId());

            if (textResponse.isEmpty()) {
                response.put("code", 200);
                response.put("msg", "文本信息不存在");
                response.put("data", "");
                return response;
            }

            ImageEntity image = new ImageEntity();
            image.setWidth(300);
            image.setHeight(100);
            image.setUrl(risk.get().getImage());
            image.setType(URL);

            Map<String, Object> singleRecord = new HashMap<>();
            singleRecord.put("riskImage",image);
            singleRecord.put("riskContent",textResponse.get().getContent());
            singleRecord.put("rectificationContent",detail.get().getSupplementContents());
            singleRecord.put("rectificationImage",detail.get().getImage());

            imageList.add(singleRecord);

            textResponseList.add(textResponse);
        }

        //原来的方法仍然保持
        map.put("project_name", curInfo.getProjectName());
        map.put("contruction_unit", curInfo.getConstructionUnit());
        map.put("design_unit", curInfo.getDesignUnit());
        map.put("supervision_unit", curInfo.getSupervisionUnit());
        map.put("inspection_team_name", curInfo.getInspectionTeamName());
        map.put("inspection_personnel", curInfo.getInspectionPersonnel());
        map.put("riskResponseList",textResponseList);

        //建议
        String strResponseContent = "请结合一下内容，总结存在的问题以及建议，尽量控制在100字以内:";
        for(int i=0;i<textResponseList.size();i++)
        {
            strResponseContent = strResponseContent +textResponseList.get(i).get().getContent();
        }

        String strSuggestion = moonshotService.callMoonshotAPI("sk-szywcJVpxK7xTGkX2ZE4GcdRb1tow9abyOobWbKmRj0AMpgd", strResponseContent, "请结合以上内容，总结出来存在的问题及建议");
        map.put("suggestion", strSuggestion);

        map.put("imageList", imageList);

        SecurityRiskReport riskReport = new SecurityRiskReport();

        ClassPathResource resource = new ClassPathResource("Templates/Template11_old.docx");
        // 从 InputStream 创建临时文件
        File tempFile = File.createTempFile("temp", ".docx");
        try (InputStream inputStream = resource.getInputStream(); // 获取 InputStream
             FileOutputStream fos = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        String templatePath = tempFile.getAbsolutePath();
        XWPFDocument word = WordExportUtil.exportWord07(tempFile.getAbsolutePath(), map);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        word.write(byteArrayOutputStream);

        //代替
        OSS ossClient = null;
        String url = null;
        String reportId = null;


        // 4. 上传到OSS
        reportId = UUID.randomUUID().toString();
        String fileName = reportId + ".docx"; // 添加扩展名
        ossClient = new OSSClientBuilder().build(
                ossConfig.getEndpoint(),
                ossConfig.getAccessKeyId(),
                ossConfig.getAccessKeySecret()
        );

        // 将字节数组转换为输入流
        InputStream fileInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

        // 上传文件到OSS
        ossClient.putObject(new PutObjectRequest(ossConfig.getBucketName(), fileName, fileInputStream));

        // 获取文件URL
        url = "https://" + ossConfig.getBucketName() + "." + ossConfig.getEndpoint() + "/" + fileName;


        response.put("code", 200);
        response.put("msg", "成功");
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("url", url);
        responseData.put("ReportId", reportId);
        response.put("data", responseData);
        return response;
    }

    // 读取输入流到字节数组
    public static byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int n = 0;
        while (-1 != (n = in.read(buffer))) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }
}